package com.yuyou.fn.educational.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.github.wens.framework.service.impl.SuperServiceImpl;
import com.github.wens.mybatisplus.examples.Example;
import com.github.wens.mybatisplus.plugins.Page;
import com.yuyou.fn.common.util.BeanUtils;
import com.yuyou.fn.common.util.CriteriaUtils;
import com.yuyou.fn.common.util.TimeUtils;
import com.yuyou.fn.educational.entity.Measurement;
import com.yuyou.fn.educational.mapper.MeasurementMapper;
import com.yuyou.fn.educational.service.IExternalRegDetailService;
import com.yuyou.fn.educational.service.IMeasurementService;
import com.yuyou.fn.educational.service.IStudentRegService;
import com.yuyou.fn.educational.vo.MeasurementQueryVo;
import com.yuyou.fn.educational.vo.MeasurementSaveOrUpdateVo;
import com.yuyou.fn.educational.vo.WhiltelistConfigVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * Measurement 表数据服务层接口实现类
 *
 */
@Service
public class MeasurementServiceImpl extends SuperServiceImpl<MeasurementMapper, Measurement,Long> implements IMeasurementService {


    @Resource
    private IStudentRegService studentRegService;

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @Resource
    private IExternalRegDetailService externalRegDetailService;


    @Override
    public Measurement saveOrUpdate(MeasurementSaveOrUpdateVo measurementSaveOrUpdateVo) {
        Measurement measurement=new Measurement();
        BeanUtils.copyProperties(measurement,measurementSaveOrUpdateVo);
        measurement.setUpdateTime(TimeUtils.now());
        if (measurement.getMeasurementId()!=null){
            this.updateSelectiveById(measurement);
        }else {
            if(measurementSaveOrUpdateVo.getExternalScoreType() == null ){
                measurementSaveOrUpdateVo.setExternalScoreType(0);
            }
            measurement.setCreateTime(TimeUtils.now());
            this.insertSelective(measurement);
        }
        return measurement;
    }


    @Override
    public Measurement findMinLevelByStudentScore(MeasurementQueryVo measurementQueryVo, Double studentScore) {
        Example<Measurement> example=Measurement.createExample();
        Example.Criteria criteria=example.createCriteria();
        CriteriaUtils.fillCondition(criteria,measurementQueryVo);
        criteria.andLessThanOrEqualTo("passingScore",studentScore);
        example.orderBy("level");
        return  this.findOneByExample(example);
    }


    @Override
    public Page<Measurement> findMeasurePageByQuery(MeasurementQueryVo measurementQueryVo,int pageNo,int pageSize) {
        Example<Measurement> example=Measurement.createExample();
        Example.Criteria criteria=example.createCriteria();
        CriteriaUtils.fillCondition(criteria,measurementQueryVo);
        example.orderBy("createTime").desc();
        return this.findPageByExample(example,pageNo,pageSize);
    }

    @Override
    public void updateWhiltelist(final Long measurementId, WhiltelistConfigVo whiltelistConfig) {
        Validate.notNull(measurementId);
        Validate.notNull(whiltelistConfig);
        Measurement u = new Measurement();
        u.setMeasurementId(measurementId);
        u.setWhitelistConfig(JSONObject.toJSONString(whiltelistConfig , SerializerFeature.WriteNonStringValueAsString ).replaceAll("(\\d+)" , "\"$1\""));
        updateSelectiveById(u);

        Measurement measurement = findById(measurementId);
        List<Long> studentIds  = studentRegService.findRegStudentIds( measurement.getAreaTeamId(), measurement.getSubjectId() , whiltelistConfig.getPeriodIds(),whiltelistConfig.getGradeIds(),whiltelistConfig.getLevels(),whiltelistConfig.getCampusIds() );

        String key = String.format("whiltelist:measurement:%d" , measurementId );
        redisTemplate.delete(key);
        HashOperations<String, String, String > hashOperations = redisTemplate.opsForHash();
        Map<String,String> map = new HashMap<>();
        for(Long studentId : studentIds ){
            map.put(String.valueOf(studentId) ,"Y" );
        }
        hashOperations.putAll( key , map );

    }

    @Override
    public boolean isInWhiltelist(Measurement measurement, Long studentId) {
        String key = String.format("whiltelist:measurement:%d" , measurement.getMeasurementId() );
        HashOperations<String, String, String > hashOperations = redisTemplate.opsForHash();
        String r  = hashOperations.get(key , String.valueOf(studentId) );

        boolean isYes = r == null ? false : "Y".equals(r);

        //处理tms报读
        if( !isYes && StringUtils.isNotEmpty(measurement.getWhitelistConfig()) ){
            WhiltelistConfigVo whiltelistConfigVo = JSONObject.parseObject(measurement.getWhitelistConfig(), WhiltelistConfigVo.class);
            long l  = externalRegDetailService.countByStudentIdPeriodIdsGradeIdsLevels(studentId, whiltelistConfigVo.getPeriodIds(),whiltelistConfigVo.getGradeIds(),whiltelistConfigVo.getLevels() );
            isYes = l > 0 ?  true : false ;
        }


        return isYes;

    }

    @Override
    public void deleteMeasurement(List<Long> measurementIds) {
        //
        deleteBatchIds(measurementIds);
        List<String> ids = new ArrayList<>(measurementIds.size());
        for(Long id : measurementIds ){
            ids.add(String.format("whiltelist:measurement:%d" , id ));
        }
        //
        redisTemplate.delete(ids);
    }

    //@Cacheable("Cache_findMeasureByPeriodIdFromCache")
    @Override
    public List<Measurement> findMeasureByPeriodIdFromCache(Long periodId) {
        return findMeasureByPeriodId(periodId);
    }

    @Override
    public List<Measurement> findMeasureByPeriodId(Long periodId) {
        Example<Measurement> example = Measurement.createExample();
        example.createCriteria().andEqualTo("periodId" ,periodId );
        example.orderBy("passingScore").asc();
        return findListByExample(example);
    }

    @Override
    public boolean hasBindThisExamPaperId(Long examPaperId) {
        Example<Measurement> example = Measurement.createExample();
        example.createCriteria().andLike("examConfig","%" + examPaperId + "%");
        return countByExample(example) > 0 ;
    }

    @Cacheable("Cache_findReachMeasurementForScore")
    @Override
    public List<Measurement> findReachMeasurementForScore(Long campusId, Long gradeId, Long subjectId, Integer score) {
        Example<Measurement> example = Measurement.createExample();
        example.createCriteria().andEqualTo("gradeId",gradeId).andEqualTo("subjectId" , subjectId ).andLessThanOrEqualTo("passingScore" ,score ).andLike("campusIds","%" + campusId + "%");
        return findListByExample(example);
    }
}